<?php

/**
 * 简易文件缓存类
 */
class SimpleFileCache {
    
    /**
     * 配置项
     * @var type 
     */
    private $_option = [];

    /**
     * 构造函数
     *
     * @param  array  $option
     * @throws Exception
     */
    public function __construct() {

        $option = [];
        
        // 默认缓存时间
        $option['life_time'] = 0;

        // 缓存目录
        if (is_dir('/tmp')) {
            $option['cache_dir'] = '/tmp/sf-cache';
        } elseif (strtoupper(substr(PHP_OS,0,3)) === 'WIN') {
            $option['cache_dir'] = 'c:\\tmp\\sf-cache';
        } else {
            $option['cache_dir'] = dirname(__FILE__).'/tmp/sf-cache';
        }
        if (!is_dir($option['cache_dir'])) {
            $ret = mkdir($option['cache_dir'], 0777, true);
            if (false === $ret) {
                throw new Exception('auto create cache dir failed: '.$option['cache_dir']);
            }
        }

        // 目录层级
        $option['cache_dir_level'] = 2;
        
        $this->_option = $option;
    }

    /**
     * 保存缓存资料
     *
     * @param  mixed   $value
     * @param  string  $id
     * @return boolean
     * @throws Exception
     */
    public function set($id, $data, $expired = null) {

        if (null === $expired) {
            $expired = $this->_option['life_time'];
        }

        $saveData = array(
            'id' => $id,
            'expired' => time() + ($expired ? $expired : 864000000),
            'data' => $data
        );
        $cacheFile = $this->_getFileName($id);
        if (!is_dir(dirname($cacheFile))) {
            mkdir(dirname($cacheFile), 0777, true);
        }
        return file_put_contents($cacheFile, $this->_encodeData($saveData));
    }

    /**
     * 加载缓存数据
     *
     * @param  string   $id
     * @return mixed|false
     */
    public function get($id) {

        $cacheFile = $this->_getFileName($id);
        if (is_file($cacheFile) && ($data = file_get_contents($cacheFile))) {
            $data = $this->_decodeData($data);
            if (!is_array($data) || $data['expired'] < time() || $data['id'] != $id) {
                unlink($cacheFile);
                return false;
            }
            return $data['data'];
        }
        return false;
    }

    /**
     * 移除缓存数据
     *
     * @param  string  $id
     * @return boolean
     */
    public function delete($id) {

        return unlink($this->_getFileName($id));
    }

    /**
     * 将任意数据编码为字符串
     * @param <type> $data
     */
    private function _encodeData($data) {

        return serialize($data);
    }

    /**
     * 将编码字符串解码
     * @param <type> $data
     * @return <type>
     */
    private function _decodeData($data) {

        return unserialize($data);
    }

    /**
     * 获取缓存文件名
     *
     * @param  string  $id
     * @return string
     */
    protected function _getFileName($id) {

        $path = $this->_option['cache_dir'];
        $name = substr(md5($id), 8, 8);
        $hash = abs(crc32($name));
        $levels = array(1009, 1013, 1019, 1031);
        for ($i = 0; $i < $this->_option['cache_dir_level']; $i++) {
            $path = $path . DIRECTORY_SEPARATOR . ($hash % $levels[$i]);
        }

        return $path .DIRECTORY_SEPARATOR . $name . '.cache';
    }
}